/**
 ******************************************************************************
 * @file    a7680c_at_modem.h
 * @author  summDy
 * @version V1.0.0
 * @date    04-07-2025
 * @brief   Brief description of the file
 ******************************************************************************
 * @attention
 *
 ******************************************************************************
 */

/**
 * | 优点   | 描述                                                         |
   | ---- | ---------------------------------------------------------- |
   | 类型安全 | 使用 `enum class` 明确标记参数类型，避免误用                              |
   | 统一封装 | 不管参数是字符串、整数还是浮点数，都可统一包装为 `AtArgumentValue`                 |
   | 通用性强 | 可用于任何 AT 命令响应解析，包括 `+CSQ`, `+CGATT`, `+QIOPEN`, `+QIRD`, 等 |
   | 易于扩展 | 后续可扩展支持 `bool`, `hex`, `list`, `nested` 类型等                |

 */

#ifndef _A7680C_AT_MODEM_H_
#define _A7680C_AT_MODEM_H_

#include <cstddef>
#include <driver/gpio.h>
#include <driver/uart.h>
#include <freertos/FreeRTOS.h>
#include <freertos/event_groups.h>
#include <freertos/queue.h>
#include <freertos/task.h>
#include <functional>
#include <list>
#include <mutex>
#include <string>
#include <vector>

#define AT_EVENT_DATA_AVAILABLE BIT1
#define AT_EVENT_COMMAND_DONE   BIT2
#define AT_EVENT_COMMAND_ERROR  BIT3
#define AT_EVENT_NETWORK_READY  BIT4

#define DEFAULT_COMMAND_TIMEOUT 3000
#define DEFAULT_BAUD_RATE       115200
#define DEFAULT_UART_NUM        UART_NUM_1

struct AtArgumentValue {
  enum class Type {
    String, // 字符串类型，例如 "+CSQ: "25,99""
    Int,    // 整数类型，例如 "+CPIN: 1"
    Double  // 浮点数类型，例如 "+GPS: 123.4567"
  };
  Type        type;         // 当前参数的实际类型
  std::string string_value; // 当 type = String 时有效
  int         int_value;    // 当 type = Int 时有效
  double      double_value; // 当 type = Double 时有效
};

// 这是一个函数类型，用于 处理解析后的 AT 响应命令与参数列表。
typedef std::function<void(const std::string &command, const std::vector<AtArgumentValue> &arguments)>
    CommandResponseCallback;

class A7680cAtModem {
public:
  A7680cAtModem(int tx_pin = GPIO_NUM_41, int rx_pin = GPIO_NUM_42, size_t rx_buffer_size = 2048);
  ~A7680cAtModem();

  std::string EncodeHex(const std::string &data);
  std::string DecodeHex(const std::string &data);
  void        EncodeHexAppend(std::string &dest, const char *data, size_t length);
  void        DecodeHexAppend(std::string &dest, const char *data, size_t length);

  bool Command(const std::string command, int timeout_ms = DEFAULT_COMMAND_TIMEOUT);
  std::list<CommandResponseCallback>::iterator RegisterCommandResponseCallback(CommandResponseCallback callback);
  void UnregisterCommandResponseCallback(std::list<CommandResponseCallback>::iterator iterator);

  void OnMaterialReady(std::function<void()> callback);
  void Reset();
  void ResetConnections();
  void SetDebug(bool debug);
  bool SetBaudRate(int new_baud_rate);
  int  WaitForNetworkReady();

private:
  std::mutex  mutex_;
  std::mutex  command_mutex_;
  bool        debug_         = false;
  bool        network_ready_ = false;
  std::string ip_address_;
  std::string iccid_;
  std::string carrier_name_;

  int csq_                = -1;
  int registration_state_ = 0;
  int pin_ready_          = 0;

  std::string        rx_buffer_;
  size_t             rx_buffer_size_;
  uart_port_t        uart_num_;
  int                tx_pin_;
  int                rx_pin_;
  int                baud_rate_;
  TaskHandle_t       event_task_handle_   = nullptr;
  TaskHandle_t       receive_task_handle_ = nullptr;
  QueueHandle_t      event_queue_handle_  = nullptr;
  EventGroupHandle_t event_group_handle_  = nullptr;
  std::string        last_command_;
  std::string        response_;

  void EventTask();
  void ReceiveTask();

  bool ParseResponse();
  bool DetectBaudRate();
  void NotifyCommandResponse(const std::string &command, const std::vector<AtArgumentValue> &arguments);

  std::list<CommandResponseCallback> on_data_received_;
  std::function<void()>              on_material_ready_;
};

#endif
